﻿using Sidvall.Collections;
using Sidvall.WorkItemManager.Net.Services.V1;
using Sidvall.WorkItemManager.Workflow;
using System.Linq;

namespace Sidvall.WorkItemManager.Worker
{
    public static class Program
    {
        #region Public Members

        public static void Main(string[] args)
        {
            WorkItemContext context;

            RegisterTypes();
            context = null;
            try
            {
                var filePath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "ExecutionContext.txt");
                var executionContext = WorkItemExecutionContext.GetItemAsync(filePath).Result;
                context = WorkItemContext.GetWorkItemContext(Properties.Settings.Default.Arguments, args, executionContext);
                var serverConnection = ServerConnection.Deserialize(Properties.Settings.Default.ServerConnection);
                Sidvall.WorkItemManager.SystemContext.Current.AddServerConnection(serverConnection);
                Sidvall.WorkItemManager.SystemContext.Current.UserConfiguration = new UserConfiguration();
                var identityProvider = IdentityProvider.Deserialize(Properties.Settings.Default.IdentityProvider);
                if ((identityProvider != null) && (!string.IsNullOrWhiteSpace(identityProvider.STSAddress)))
                {
                    Sidvall.WorkItemManager.SystemContext.Current.UserConfiguration.STSAddress = identityProvider.STSAddress;
                    Sidvall.WorkItemManager.SystemContext.Current.UserConfiguration.STSClientId = identityProvider.STSClientId;
                    Sidvall.WorkItemManager.SystemContext.Current.UserConfiguration.STSClientSecret = identityProvider.STSClientSecret;
                    var loggedOn = Sidvall.WorkItemManager.SystemContext.Current.AuthenticationStrategy.NewAuthenticationHeaderFromResourceOwnerPasswordAsync(identityProvider.UserName,
                        identityProvider.Password, null).Result;
                }

                System.Console.WriteLine("Executing worker(s): " + context.WorkerIds.JoinToString(", "));
                System.AppDomain.CurrentDomain.AssemblyResolve += new System.ResolveEventHandler(AssemblyResolveEventHandler);
                Sidvall.SystemContext.Current.TypeCache.AddAssembliesAsync(context.PluginPath, null, Sidvall.IO.SearchOption.AllDirectories).Wait();
                var manager = Sidvall.WorkItemManager.Workflow.WorkManager.GetWorkManagerAsync(null).Result;

                var task = manager.ExecuteAsync(context);
                task.Wait();

                System.Console.WriteLine("Saving execution context...");
                executionContext.SaveItemAsync(filePath).Wait();

                System.Console.WriteLine("Done.");
            }
            catch (System.Exception ex)
            {
                Sidvall.WorkItemManager.SystemContext.Current.LogManager.WriteAsync(ex, Sidvall.Logging.LogCategories.Application).Wait();
                System.Console.WriteLine(Sidvall.SystemContext.Current.SystemExceptionManager.GetMessage(ex));
            }
            if ((context == null) || (context.IsTestRun))
                System.Console.ReadLine();
        }

        #endregion
        #region Private Members

        #region AssemblyResolveEventHandler

        private static System.Reflection.Assembly AssemblyResolveEventHandler(object sender, System.ResolveEventArgs args)
        {
            var items = System.AppDomain.CurrentDomain.GetAssemblies();
            var item = (from o in items
                        where (o.FullName == args.Name)
                        select o).FirstOrDefault();
            if (item == null)
            {
                items = System.AppDomain.CurrentDomain.GetAssemblies();
                item = (from o in items
                        where (o.GetName().Name == args.Name)
                        select o).FirstOrDefault();
            }
            if (item == null)
            {
                System.Console.WriteLine("Could not find the assembly:" + args.Name);
            }
            return item;
        }

        #endregion
        #region RegisterTypes

        private static void RegisterTypes()
        {
            // Framework
            var authorizationProvider = new Sidvall.Security.PublicAuthorizationProvider();
            Sidvall.SystemContext.Current = new Sidvall.SystemContext()
            {
                //AccountManager = new Sidvall.Security.AccountManager(new Sidvall.WorkItemManager.Security.AccountProvider()),
                AuthorizationManager = new Sidvall.Security.AuthorizationManager(authorizationProvider),
                AuthenticationManager = new Sidvall.Security.AuthenticationManager(new Sidvall.Security.AuthenticationProvider()),
                AuthenticationStrategyManager = new Sidvall.Security.AuthenticationStrategyManager(new Sidvall.Security.AuthenticationStrategy()),
                //CacheManager = new Sidvall.Caching.CacheManager(new Sidvall.Caching.MemoryCache()),
                ClaimManager = new Sidvall.Security.ClaimManager(new Sidvall.Security.ClaimsPrincipalManager()),
                CodeManager = new Sidvall.Reflection.CodeManager(new Sidvall.Reflection.Code()),
                UserExceptionManager = new Sidvall.ExceptionHandling.ExceptionManager(new Sidvall.ExceptionHandling.UserExceptionProvider()),
                SystemExceptionManager = new Sidvall.ExceptionHandling.ExceptionManager(new Sidvall.ExceptionHandling.SystemExceptionProvider()),
                HttpClientFactory = new Sidvall.Net.HttpClientFactory(),
                LauncherManager = new Sidvall.SystemEnvironment.LauncherManager(new Sidvall.SystemEnvironment.Windows.Launcher()),
                LogManager = new Sidvall.Logging.LogManager(new Sidvall.Logging.EL.Log()),
                PackageManager = new Sidvall.SystemEnvironment.PackageManager(new Sidvall.SystemEnvironment.Windows.Package()),
                SmtpClientManager = new Sidvall.Net.Mail.SmtpClientManager(new Sidvall.Net.Mail.SmtpClient()),
                SmsClientManager = new Sidvall.Net.Sms.SmsClientManager(new Sidvall.Net.Sms.SmsClient()),
                SoapClientFactory = new Sidvall.Net.SoapClientFactory(),
                SqlManager = new Sidvall.Data.SqlManager(new Sidvall.Data.SqlServerProvider()),
                SystemStorageManager = new Sidvall.IO.StorageManager(new Sidvall.IO.FileSystem()),
                TransactionScopeFactory = new Sidvall.Data.TransactionScopeFactory(),
                TypeCache = new Sidvall.Reflection.TypeCache(),
                UserManager = new Sidvall.Security.UserManager(authorizationProvider),
                UserResponseStrategyManager = new Sidvall.Security.UserResponseStrategyManager(new Sidvall.Security.UserResponseStrategy()),
                //UserStorageManager = new Sidvall.IO.StorageManager(new Sidvall.IO.Storage.LocalStorage()),

                // Client
                PrincipalContextManager = new Sidvall.Security.PrincipalContextManager(new Sidvall.Security.PrincipalContextProvider()),
                PrincipalManager = new Sidvall.Security.PrincipalManager(new Sidvall.Security.PrincipalProvider()),

                // Host specific
                CultureManager = new Sidvall.Globalization.CultureManager(new Sidvall.Globalization.CultureProvider()),
                ResourceManager = new Sidvall.Resources.ResourceManager(new Sidvall.Resources.ResourceProvider()),
                SettingsManager = new Sidvall.Configuration.SettingsManager(new Sidvall.WorkItemManager.Worker.Configuration.ApplicationSettings()),
            };
            Sidvall.WorkItemManager.SystemContext.Current.InitializeAuthenticationStrategy();
        }

        #endregion

        #endregion
    }
}
